package cn.ysbd.datafactory.engine;

import cn.ysbd.datafactory.config.JedisPoolFactory;
import cn.ysbd.datafactory.config.RedisKey;
import cn.ysbd.datafactory.engine.entity.LogData;
import cn.ysbd.datafactory.engine.service.LoggerFieldService;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import io.krakens.grok.api.Grok;
import io.krakens.grok.api.GrokCompiler;
import io.krakens.grok.api.Match;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import redis.clients.jedis.Jedis;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * @Author: YinHeng
 * @Description: 数据处理
 * @DateTime: 2022/9/2 15:49
 */
public class LogHandler implements Runnable {

    private static final Logger LOGGER = LoggerFactory.getLogger(LogHandler.class.getName());

    private static final String REQUEST_OK = "success";

    private String text;

    private LoggerFieldService loggerFieldService;
    /**
     * 是否是第一条日志
     */
    private boolean isFirst;

    public LogHandler(String text, LoggerFieldService loggerFieldService, boolean isFirst) {
        this.text = text;
        this.loggerFieldService = loggerFieldService;
        this.isFirst = isFirst;
    }

    @Override
    public void run() {

        JSONObject jsonObject = JSON.parseObject(text);
        //获取响应码
        if (!REQUEST_OK.equals(jsonObject.getString("status"))) {
            LOGGER.warn("日志查询失败，请求结果：{}", text);
        }
        //获取响应数据
        JSONObject data = jsonObject.getJSONObject("data");
        JSONObject stats = data.getJSONObject("stats");
        JSONArray result = data.getJSONArray("result");
        if (result.size() == 0) {
            return;
        }

        Long startTsNs = null;
        List<LogData> rows = new ArrayList<>();
        for (int i = 0; i < result.size(); i++) {
            JSONObject resultItem = result.getJSONObject(i);
            JSONObject stream = resultItem.getJSONObject("stream");
            String logTag = stream.getString("app");
            JSONArray values = resultItem.getJSONArray("values");

            for (int k = 0; k < values.size(); k++) {
                JSONArray valueItem = values.getJSONArray(k);
                Long tsNs = valueItem.getLong(0);
                startTsNs = tsNs;
                String logMessage = valueItem.getString(1);
                LOGGER.debug("logMessageItem:{}", logMessage);

                GrokCompiler grokCompiler = GrokCompiler.newInstance();
                // 进行注册, registerDefaultPatterns()方法注册的是Grok内置的patterns
                grokCompiler.registerDefaultPatterns();
                // 添加自定的正则表达式，解析日期（例如：2021-07-07 13:45:39.210）
                grokCompiler.register("DATETIME", "[0-9,\\.\\-: ]+");
                Grok grok = grokCompiler.compile("%{DATETIME:datetime}\\S*\\s*\\[%{NOTSPACE:thread}\\]\\S*\\s*%{LOGLEVEL:level}\\S*\\s*%{NOTSPACE:classed} \\S*\\s*%{GREEDYDATA:message}");
                //2022-11-17 15:30:34.500 ysbedo-gateway [nioEventLoopGroup-3-23] INFO  y.gateway.handler.GisAgentHandler - agent-url-end:/agent/access-key/test/serv-code/1585840776845271041/MapServer/tile/7/23/101
                Match grokMatch = grok.match(logMessage);
                // 获取结果
                Map<String, Object> messageMap = grokMatch.capture();
                if (messageMap.size() != 0) {
                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSSSSS");
                    LogData logData = new LogData();
                    logData.setTsNs(tsNs);
                    logData.setThread((String) messageMap.get("thread"));
                    logData.setLogTag(logTag);
                    logData.setLevel((String) messageMap.get("level"));
                    logData.setClassed((String) messageMap.get("classed"));
                    String dateStr = (String) messageMap.get("datetime");
                    try {
                        logData.setDatetime(sdf.parse(dateStr));
                    } catch (ParseException e) {
                        throw new RuntimeException(e);
                    }
                    logData.setMessage((String) messageMap.get("message"));
                    rows.add(logData);
                }
            }
        }
        //第一次加载并且入库数据为零，则存储加载时间点
        if (rows.size() == 0 && isFirst){
            Jedis jedis = null;
            try {
                assert startTsNs != null;
                jedis = JedisPoolFactory.getJedis();
                jedis.setex(RedisKey.LOG_DATA_START_TIME, 3600L, startTsNs.toString());
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                if (jedis != null) {
                    jedis.close();
                }
            }
            return;
        }
        loggerFieldService.saveBatch(rows);


    }

    public static void main(String[] args) throws ParseException {
        String msg = "2022-11-17 17:03:45.965 ysbedo-gateway [nioEventLoopGroup-3-76] INFO  y.gateway.handler.GisAgentHandler - {\"servCode\":\"1585556212612669441\",\"tackTime\":2686817117122775,\"accessKey\":\"test\",\"realUrl\":\"http://10.52.1.38:6080/geoscene/rest/services/专题数据/fsl/FeatureServer/0/query?f=json&geometry=%7B%22xmin%22%3A109.68749999999999%2C%22ymin%22%3A22.499999999999996%2C%22xmax%22%3A112.49999999999999%2C%22ymax%22%3A25.312499999999996%7D&maxAllowableOffset=0.005493164062499999&orderByFields=objectid_12&outFields=*&outSR=4490&quantizationParameters=%7B%22extent%22%3A%7B%22spatialReference%22%3A%7B%22latestWkid%22%3A4490%2C%22wkid%22%3A4490%7D%2C%22xmin%22%3A109.68749999999999%2C%22ymin%22%3A22.499999999999996%2C%22xmax%22%3A112.49999999999999%2C%22ymax%22%3A25.312499999999996%7D%2C%22mode%22%3A%22view%22%2C%22originPosition%22%3A%22upperLeft%22%2C%22tolerance%22%3A0.005493164062499999%7D&resultType=tile&returnExceededLimitFeatures=false&spatialRel=esriSpatialRelIntersects&where=1%3D1&geometryType=esriGeometryEnvelope&inSR=4490\",\"requestPath\":\"/agent/access-key/test/serv-code/1585556212612669441/FeatureServer/query?f=json&geometry=%7B%22xmin%22%3A109.68749999999999%2C%22ymin%22%3A22.499999999999996%2C%22xmax%22%3A112.49999999999999%2C%22ymax%22%3A25.312499999999996%7D&maxAllowableOffset=0.005493164062499999&orderByFields=objectid_12&outFields=*&outSR=4490&quantizationParameters=%7B%22extent%22%3A%7B%22spatialReference%22%3A%7B%22latestWkid%22%3A4490%2C%22wkid%22%3A4490%7D%2C%22xmin%22%3A109.68749999999999%2C%22ymin%22%3A22.499999999999996%2C%22xmax%22%3A112.49999999999999%2C%22ymax%22%3A25.312499999999996%7D%2C%22mode%22%3A%22view%22%2C%22originPosition%22%3A%22upperLeft%22%2C%22tolerance%22%3A0.005493164062499999%7D&resultType=tile&returnExceededLimitFeatures=false&spatialRel=esriSpatialRelIntersects&where=1%3D1&geometryType=esriGeometryEnvelope&inSR=4490\"}\n";
        GrokCompiler grokCompiler = GrokCompiler.newInstance();

        long time = System.currentTimeMillis() - (48L * 3600 * 1000);
        System.out.println("time:" + time);
        // 进行注册, registerDefaultPatterns()方法注册的是Grok内置的patterns
        grokCompiler.registerDefaultPatterns();
        // 添加自定的正则表达式，解析日期（例如：2021-07-07 13:45:39.210）
        grokCompiler.register("DATETIME", "[0-9,\\.\\-: ]+");
        /*%{DATETIME:datetime} \s*%{LOGLEVEL:level} %{INT:pid} --- \[%{NOTSPACE:thread}\] %{NOTSPACE:classed}\s*:%{GREEDYDATA:message}*/
        Grok grok = grokCompiler.compile("%{DATETIME:datetime}\\S*\\s*\\[%{NOTSPACE:thread}\\]\\S*\\s*%{LOGLEVEL:level}\\S*\\s*%{NOTSPACE:classed} \\S*\\s*%{GREEDYDATA:message}");

        Match grokMatch = grok.match(msg);
        // 获取结果
        Map<String, Object> messageMap = grokMatch.capture();

        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
        String dateStr = (String) messageMap.get("datetime");
        Date date = sdf.parse(dateStr);


        System.out.println(JSON.toJSONString(messageMap));
        String message = (String) messageMap.get("message");
        JSONObject jsonObject = JSON.parseObject(message);
        jsonObject.get("servCode");
        System.out.println("message:" + jsonObject.getString("accessKey"));
    }
}
